package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"math/rand"
	"strings"

	"log"
	"mytest/cmd/node"
	"net"
	"time"
)

func getAddClusterMsg(source node.NodeInfo, dst node.NodeInfo, msg string) node.AddToClusterMessage {
	return node.AddToClusterMessage{
		Source:  source,
		Dest:    dst,
		Message: msg,
	}
}
func connectToCluster(me node.NodeInfo, dst node.NodeInfo) bool {
	//连接到socket的相关细节信息
	connOut, err := net.DialTimeout("tcp", dst.NodeIpAddr+":"+dst.Port, time.Duration(10)*time.Second)
	if err != nil {
		log.Println("不能连接到集群", err)
		return false
	} else {
		fmt.Println("连接到集群")
		text := "hi 请添加我到集群"
		requestMessage := getAddClusterMsg(me, dst, text)
		//把请求信息写入conn
		err := json.NewEncoder(connOut).Encode(&requestMessage)
		if err != nil {
			log.Println("send err:", err)
		}
		decoder := json.NewDecoder(connOut)
		var responseMessage node.AddToClusterMessage
		decoder.Decode(&responseMessage)
		fmt.Println("得到响应的数据", responseMessage)
		return true
	}
}

//本节点连接目的地成功或者 成功第一个主节点后 需要开启监听
//开始监听别的节点在未来可能对它自身的连接
func listenOnPort(me node.NodeInfo) {
	listen, _ := net.Listen("tcp", fmt.Sprintf(":%v", me.Port))
	//接收连接
	for {
		connIn, err := listen.Accept()
		if err != nil {
			log.Println("accept err:", err)
		} else {
			var requestMessage node.AddToClusterMessage
			json.NewDecoder(connIn).Decode(&requestMessage)
			fmt.Println("Got Request:", requestMessage.String())

			text := "已经添加你到集群"
			encoder := json.NewEncoder(connIn)
			responseMessage := getAddClusterMsg(me, requestMessage.Source, text)
			encoder.Encode(&responseMessage)
			connIn.Close()
		}
	}
}
func main() {
	//当第一个节点启动用这个命令来将第一个节点作为主节点
	makeMasterOnError := flag.Bool("makeMasterOnError", true, "make this node master if unable to connect to the cluster ip provided.")
	//设置要连接的目的地ip地址
	clusterip := flag.String("clusterip", "127.0.0.1:8001", "ip address of any node to connnect")
	//设置要连接的目的地端口号
	myport := flag.String("myport", "8001", "ip address to run this node on. default is 8001.")
	flag.Parse()
	rand.Seed(time.Now().UTC().Unix())
	myId := rand.Intn(9999)
	fmt.Println(myId)

	//获取ip
	fmt.Println("============ip============")
	myIP, _ := net.InterfaceAddrs()
	for _, v := range myIP {
		fmt.Println(v.String())
	}
	//fmt.Println(myIP)
	//创建nodeInfo结构体
	fmt.Println("========node=============")
	me := node.NodeInfo{NodeID: myId, NodeIpAddr: "127.0.0.1", Port: *myport}
	fmt.Println(me.String())
	dest := node.NodeInfo{NodeID: myId, NodeIpAddr: strings.Split(*clusterip, ":")[0], Port: strings.Split(*clusterip, ":")[1]}
	//尝试连接到集群，在已连接的情况下向集群发送请求
	ableToConnect := connectToCluster(me, dest)
	//如果dest节点不存在，则me节点为主节点启动，否则直接退出系统
	if ableToConnect || (!ableToConnect && *makeMasterOnError) {
		if *makeMasterOnError {
			fmt.Println("将启动me节点为主节点")
		}
		listenOnPort(me)
	} else {
		fmt.Println("正在退出系统，请设置me节点为主节点")
	}

}
